
package kotlinx.coroutines.script.tes

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.*
import java.nio.charset.StandardCharsets

object FileUtils {
        fun cacheDir(child: String) = File(appContext.cacheDir, child).also { it.mkdirs() }
        fun externalCacheDir(child: String) =
            File(appContext.externalCacheDir, child).also { it.mkdirs() }

        fun filesDir(child: String) = File(appContext.filesDir, child).also { it.mkdirs() }

        suspend fun writeBitmapToDisk(file: File, data: Bitmap, quality: Int = 100) {
            withContext(Dispatchers.IO) {
                var stream: FileOutputStream? = null
                try {
                    if (!file.exists()) file.createNewFile()
                    stream = FileOutputStream(file)
                    data.compress(Bitmap.CompressFormat.JPEG, 100, stream)
                } catch (e: Throwable) {
                    if (isDebug) e.printStackTrace()
                    file.delete()
                } finally {
                    stream?.closeQuietly()
                }
            }
        }

        fun syncWriteBitmapToDisk(file: File, data: Bitmap, quality: Int = 100) {
            var stream: FileOutputStream? = null
            try {
                if (!file.exists()) file.createNewFile()
                stream = FileOutputStream(file)
                data.compress(Bitmap.CompressFormat.JPEG, 100, stream)
            } catch (e: Throwable) {
                if (isDebug) e.printStackTrace()
                file.delete()
            } finally {
                stream?.closeQuietly()
            }
        }

        suspend fun readBitmapFromDisk(file: File?): Bitmap? {
            if (file == null) return null
            return withContext(Dispatchers.IO) {
                BitmapFactory.decodeFile(file.absolutePath)
            }
        }

        fun syncReadBitmapFromDisk(file: File) = BitmapFactory.decodeFile(file.absolutePath)

        suspend fun write(file: File, data: String) {
            withContext(Dispatchers.IO) {
                syncWrite(file, data)
            }
        }

        fun syncWrite(file: File, data: String) {
            var stream: FileOutputStream? = null
            var outputStream: OutputStreamWriter? = null
            var writer: BufferedWriter? = null
            try {
                if (!file.exists()) file.createNewFile()
                stream = FileOutputStream(file)
                outputStream = OutputStreamWriter(stream, StandardCharsets.UTF_8)
                writer = BufferedWriter(outputStream)
                writer.append(data)
            } catch (e: Throwable) {
                if (isDebug) e.printStackTrace()
                file.delete()
            } finally {
                writer?.closeQuietly()
                outputStream?.closeQuietly()
                stream?.closeQuietly()
            }
        }

        suspend fun read(file: File?): String? = withContext(Dispatchers.IO) {
            return@withContext syncRead(file)
        }

        fun syncRead(file: File?): String? {
            if (file == null) return null
            if (!file.exists()) return null
            var stream: FileInputStream? = null
            var inputStream: InputStreamReader? = null
            var reader: BufferedReader? = null
            try {
                stream = FileInputStream(file)
                inputStream = InputStreamReader(stream, StandardCharsets.UTF_8)
                reader = BufferedReader(inputStream)
                var line: String?
                val result = StringBuffer()
                while (reader.readLine().also { line = it } != null) {
                    result.append(line)
                }
                return result.toString()
            } catch (e: Throwable) {
                if (isDebug) e.printStackTrace()
            } finally {
                reader?.closeQuietly()
                inputStream?.closeQuietly()
                stream?.closeQuietly()
            }
            return null
        }

        fun copy(inputStream: InputStream?, outputStream: OutputStream?) {
            if (inputStream == null) return
            if (outputStream == null) return
            try {
                var read: Int
                val bytes = ByteArray(1024)
                while (inputStream.read(bytes).also { read = it } != -1) {
                    outputStream.write(bytes, 0, read)
                }
            } catch (e: Throwable) {
                e.printStackTrace()
            } finally {
                inputStream.closeQuietly()
                outputStream.closeQuietly()
            }
        }
        fun size(byteCount: Int?) = size(byteCount?.toLong())
        private fun size(byteCount: Long?): String {
            if (byteCount == null) return ""
            if (byteCount < 0) return ""
            if (byteCount < 1024) return "${byteCount}B"
            if (byteCount < 1048576) return "${byteCount / 1024}KB"
            return "${byteCount / 1048576f}MB"
        }
}